﻿Imports System.Data
Imports DynamicDataEntryModel
Imports System.Reflection
Imports System.Reflection.Emit

Namespace App_Code

    Public Class HotDeal
        Private _intHotDealId As Integer
        Private _strTitle As String
        Private _strQueryString As String
        Private _strDescription As String
        Private _strContents As String
        Private _tintStatusId As Byte
        Private _dtmCreated As Date
        Private _strCreator As String
        Private _strModifier As String
        Private _dtmModified As Date
        Private _dtmPublishedDate As Date
        Private _bintViewed As Int64
#Region "Constructors"
        'Sub New(ByVal intHotDealId As Integer, ByVal strTitle As String, ByVal strQueryString As String, ByVal strDescription As String, ByVal strContents As String, ByVal tintStatusId As Byte, ByVal dtmCreated As Date, ByVal strCreator As String, ByVal strModifier As String, ByVal dtmModified As Date, ByVal dtmPublishedDate As Date, ByVal bintViewed As Long)
        '    _intHotDealId = intHotDealId
        '    _strTitle = strTitle
        '    _strQueryString = strQueryString
        '    _strDescription = strDescription
        '    _strContents = strContents
        '    _tintStatusId = tintStatusId
        '    _dtmCreated = dtmCreated
        '    _strCreator = strCreator
        '    _strModifier = strModifier
        '    _dtmModified = dtmModified
        '    _dtmPublishedDate = dtmPublishedDate
        '    _bintViewed = bintViewed
        'End Sub

        Property HotDealId() As Integer
            Get
                Return _intHotDealId
            End Get
            Set(value As Integer)
                _intHotDealId = value
            End Set
        End Property
        Property Title() As String
            Get
                Return _strTitle
            End Get
            Set(value As String)
                _strTitle = value
            End Set
        End Property
        Property QueryString() As String
            Get
                Return _strQueryString
            End Get
            Set(value As String)
                _strQueryString = value
            End Set
        End Property
        Property Description() As String
            Get
                Return _strDescription
            End Get
            Set(value As String)
                _strDescription = value
            End Set
        End Property
        Property Contents() As String
            Get
                Return _strContents
            End Get
            Set(value As String)
                _strContents = value
            End Set
        End Property
        Property StatusId() As Byte
            Get
                Return _tintStatusId
            End Get
            Set(value As Byte)
                _tintStatusId = value
            End Set
        End Property
        Property Creator() As String
            Get
                Return _strCreator
            End Get
            Set(value As String)
                _strCreator = value
            End Set
        End Property
        Property Created() As Date
            Get
                Return _dtmCreated
            End Get
            Set(value As Date)
                _dtmCreated = value
            End Set
        End Property
        Property Modified() As Date
            Get
                Return _dtmModified
            End Get
            Set(value As Date)
                _dtmModified = value
            End Set
        End Property
        Property Modifier() As String
            Get
                Return _strModifier
            End Get
            Set(value As String)
                _strModifier = value
            End Set
        End Property
        Property PublishedDate() As Date
            Get
                Return _dtmPublishedDate
            End Get
            Set(value As Date)
                _dtmPublishedDate = value
            End Set
        End Property
        Property Viewed() As Int64
            Get
                Return _bintViewed
            End Get
            Set(value As Int64)
                _bintViewed = value
            End Set
        End Property


#End Region
#Region "Common functions"
        ''' <summary>
        ''' Get a Hot Deal by Id
        ''' </summary>
        ''' <returns>ds</returns>
        ''' <remarks></remarks>
        Protected Function GetHotDealById() As DataSet
            Try
                Using context As New DynamicDataEntryEntities()
                    Dim lstHotDeal = context.dq_HotDeals.Where(Function(h) h.HotDealID = HotDealId).Select(Function(h) h).ToList()
                    Dim ds = GetDataSetHacked(lstHotDeal)
                    Return ds
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Function
        ''' <summary>
        ''' Load Option by QuestionID
        ''' </summary>
        ''' <param name="questionId"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetOptionByQuestionId(questionId As Integer) As Object
            Try
                Using context As New DynamicDataEntryEntities()
                    'Get OptionID
                    Dim optionId = context.Option _
                                    .Where(Function(o) o.OptionID = context.dq_QuestionOption _
                                                                   .Where(Function(qO) qO.QuestionID = questionId) _
                                                                   .Select(Function(qO) qO.OptionID) _
                                                                   .FirstOrDefault()) _
                                    .Select(Function(o) o.OptionID) _
                                    .FirstOrDefault()

                    'Get OptionValue by OptionID
                    Dim lstOptions = (From ov In context.OptionValue
                                    Where ov.OptionID = optionId
                                    Select New With {ov.OptionID, ov.Text, ov.Value}).ToList
                    Return lstOptions
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Function
        ''' <summary>
        ''' Insert new Question
        ''' </summary>
        ''' <param name="questionText"></param>
        ''' <param name="controlSrc"></param>
        ''' <param name="defaultValue"></param>
        ''' <param name="answerValue"></param>
        ''' <returns>OptionID</returns>
        ''' <remarks></remarks>
        Public Function InsertNewQuestion(questionText As String, controlSrc As String, Optional defaultValue As Byte = 1, Optional answerValue As Byte = 1) As Integer
            Try
                Using context As New DynamicDataEntryEntities()
                    'TODO: Insert new Question
                    Dim q As New dq_Questions
                    q.QuestionText = questionText
                    q.ControlSrc = controlSrc
                    context.dq_Questions.AddObject(q)
                    context.SaveChanges()

                    'TODO: Insert new Option
                    Dim o As New [Option]
                    o.Name = questionText
                    o.DefaultValue = defaultValue
                    o.AnswerValue = answerValue
                    context.Option.AddObject(o)
                    context.SaveChanges()

                    'TODO: Insert new reference table QuestionOption
                    Dim qo As New dq_QuestionOption
                    qo.QuestionID = q.QuestionID
                    qo.OptionID = o.OptionID
                    context.dq_QuestionOption.AddObject(qo)
                    context.SaveChanges()
                    Return o.OptionID
                End Using
            Catch ex As Exception
                Return 0
            End Try

        End Function
        ''' <summary>
        ''' Loop all choice to insert to Option Value
        ''' </summary>
        ''' <param name="optionId"></param>
        ''' <param name="text"></param>
        ''' <param name="value"></param>
        ''' <remarks></remarks>
        Public Sub InsertOptionChoices(optionId As Integer, text As String, value As Byte)
            Try
                Using context As New DynamicDataEntryEntities()
                    Dim ov As New OptionValue
                    ov.OptionID = optionId
                    ov.Text = text
                    ov.Value = value
                    context.OptionValue.AddObject(ov)
                    context.SaveChanges()
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Sub
        ''' <summary>
        ''' Get all Hot Deals
        ''' </summary>
        ''' <returns>hotDeals</returns>
        ''' <remarks></remarks>
        Public Function GetAllHotDeals() As Object
            Try
                Using context As New DynamicDataEntryEntities()
                    Return context.GetAllHotDeals().ToList()
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Function
        ''' <summary>
        ''' Get all questions 
        ''' </summary>
        ''' <returns>questions</returns>
        ''' <remarks></remarks>
        Public Function GetAllQuestions() As Object
            Try
                Using context As New DynamicDataEntryEntities()
                    'Dim name As New ObjectParameter("Name", GetType(String))
                    Return context.GetAllQuestions().ToList
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Function
        ''' <summary>
        ''' Get Dynamic Question For Hot Deal
        ''' </summary>
        ''' <param name="paramHotDealId"></param>
        ''' <returns>Object</returns>
        ''' <remarks></remarks>
        Public Function GetDynamicQuestionsForHotDeal(ByVal paramHotDealId As Integer) As Object
            Try
                Using context As New DynamicDataEntryEntities()
                    Return context.GetDynamicQuestionsForHotDeal(paramHotDealId).ToList()
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Function
        ''' <summary>
        ''' Add new Dynamic Question
        ''' </summary>
        ''' <param name="paramHotDealId"></param>
        ''' <param name="paramQuestionId"></param>
        ''' <remarks></remarks>
        Public Sub AddDynamicQuestion(ByVal paramHotDealId As Integer, ByVal paramQuestionId As Integer)
            Try
                Using ctx As New DynamicDataEntryEntities()
                    ctx.AddDynamicQuestion(paramHotDealId, paramQuestionId)
                End Using
            Catch ex As Exception
                Throw New NotImplementedException()
            End Try
        End Sub
#End Region
#Region "Extensions functions"
        Private Function GetDataSetHacked(Of T)(ByVal list As List(Of T)) As DataSet
            Dim resultDataSet As New DataSet()
            Dim resultDataTable As New DataTable("results")
            Dim resultDataRow As DataRow = Nothing
            Dim itemProperties() As PropertyInfo = list.Item(0).GetType().GetProperties()
            Dim callPropertyValue(itemProperties.Length()) As GetPropertyDelegate(Of T)

            '
            ' Meta Data.
            ' Each item property becomes a column in the table 
            ' Build an array of Property Getters, one for each Property 
            ' in the item class. Can pass anything as [item] it is just a 
            ' place holder parameter, later we will invoke it with the
            ' correct item. This code assumes the runtime does not change
            ' the ORDER in which the proprties are returned.
            '
            itemProperties = list.Item(0).GetType().GetProperties()
            Dim i As Integer = 0

            For Each p As PropertyInfo In itemProperties
                callPropertyValue(i) = _
                    CreateGetPropertyValueDelegate(CType(list.Item(0), T), p.Name)
                resultDataTable.Columns.Add(p.Name, _
                            p.GetGetMethod.ReturnType())
                i += 1
            Next
            '    
            ' Data    
            '
            For Each item As T In list
                '
                ' Get the data from this item into a DataRow
                ' then add the DataRow to the DataTable.
                ' Eeach items property becomes a colunm.
                '
                itemProperties = item.GetType().GetProperties()
                resultDataRow = resultDataTable.NewRow()
                i = 0
                For Each p As PropertyInfo In itemProperties
                    resultDataRow(p.Name) = _
                        callPropertyValue(i).Invoke(item)
                    i += 1
                Next
                resultDataTable.Rows.Add(resultDataRow)
            Next
            '    
            ' Add the DataTable to the DataSet, We are DONE!
            '
            resultDataSet.Tables.Add(resultDataTable)
            Return resultDataSet
        End Function

        '
        ' Delegate to call DynamicMethod
        '
        Private Delegate Function GetPropertyDelegate(Of T)(ByVal item As T) As Object
        '
        ' Builds a Dynamic Method to read the peoperty of an object
        '
        Private Function CreateGetPropertyValueDelegate(Of T)(ByVal item As T, ByVal itemName As Object) As GetPropertyDelegate(Of T)

            Dim arg() As Type = {GetType(T)}
            Dim propertyInfo As PropertyInfo = item.GetType().GetProperty(CType(itemName, String), BindingFlags.Public Or BindingFlags.Instance)
            Dim getPropertyValue As DynamicMethod
            Dim ilGenerator As ILGenerator

            '
            ' Create the funciton
            '
            getPropertyValue = New DynamicMethod("_getPropertyValue", GetType(Object), arg, GetType(Integer).Module)
            '
            ' Write the body of the function.
            '
            ilGenerator = getPropertyValue.GetILGenerator()
            ilGenerator.Emit(OpCodes.Ldarg_0)
            ilGenerator.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod())
            ' Box value types.
            If Not propertyInfo.PropertyType.IsClass Then
                ilGenerator.Emit(OpCodes.Box, _
                                propertyInfo.GetGetMethod.ReturnType())
                ilGenerator.Emit(OpCodes.Ret)
            End If
            '
            ' Return the Delegate
            '
            Return CType(getPropertyValue.CreateDelegate(GetType(GetPropertyDelegate(Of T))), GetPropertyDelegate(Of T))

        End Function
#End Region

    End Class
End Namespace